package com.ssm.service.impl;

import java.nio.charset.Charset;
import java.util.HashMap;
import java.util.Map;

import org.apache.commons.beanutils.BeanUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.http.HttpEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.ssm.pojo.InvokeOpenApiParam2;
import com.ssm.service.CommonService;

import net.sf.json.xml.XMLSerializer;
import openapi.dto.ApiCommonParamDto;
import openapi.dto.ApiPublicParamDto;
import openapi.util.FastJsonUtils;
import openapi.util.SignUtil;
import openapi.util.XmlUtils;

@Service("commonService")
public class CommonServiceImpl implements CommonService {
	private static final Logger logger = LoggerFactory.getLogger(CommonServiceImpl.class);

	public static final String SIGN_METHOD_RSA = "RSA";
	public static final String SIGN_METHOD_MD5 = "MD5";

	public static final String REQ_PARAM = "reqParam";
	public static final String RESP_RESULT = "respResult";

	private Map<String, Object> reqAndRespMap = null;

	@Override
	public Map<String, Object> invokeWithSoap(InvokeOpenApiParam2 param) {
		logger.info("invokeWithSoap...");
		boolean isRest = false;

		ApiCommonParamDto dto = transferData(param);

		String xml = null;
		try {
			xml = toXml(isRest, dto);
			logger.info("================xml==================");
			logger.info(xml);
		} catch (Exception e) {
			e.printStackTrace();
		}
		String responseData = doTestSoap(param.getUrl(), xml);
		System.out.println(responseData);

		XMLSerializer xmlSerializer = new XMLSerializer();
		String xml_json = xmlSerializer.read(responseData).toString();
		System.out.println(xml_json);
		//
		JSONObject jsonObject = JSON.parseObject(xml_json);
		System.out.println();
		System.out.println(jsonObject.get("RETURN_CODE"));
		System.out.println(jsonObject.get("RETURN_STAMP"));
		System.out.println(jsonObject.get("RETURN_DATA"));
		System.out.println(jsonObject.get("RETURN_DESC"));

		reqAndRespMap = new HashMap<String, Object>();
		reqAndRespMap.put(REQ_PARAM, xml);
		reqAndRespMap.put(RESP_RESULT, responseData);

		return reqAndRespMap;
	}

	@Override
	public Map<String, Object> invokeWithRestJson(InvokeOpenApiParam2 param) {
		logger.info("invokeWithRestJson...");
		ApiCommonParamDto dto = transferData(param);
		reqAndRespMap = new HashMap<String, Object>();

		JSONObject requestJsonObj = new JSONObject();
		try {
			ApiPublicParamDto apiPublicParamDto = new ApiPublicParamDto();
			BeanUtils.copyProperties(apiPublicParamDto, dto);
			JSONObject rootJsonObject = new JSONObject();
			JSONObject hrtAttrs = (JSONObject) JSON.toJSON(apiPublicParamDto);
			rootJsonObject.put("REQUEST_DATA", FastJsonUtils.parse(param.getReqdata(), true));
			rootJsonObject.put("HRT_ATTRS", hrtAttrs);
			requestJsonObj.put("REQUEST", rootJsonObject);
			String requestMessage = requestJsonObj.toString();
			String responseData = doTestJson(param.getUrl(), requestMessage);

			reqAndRespMap.put(REQ_PARAM, requestMessage);
			reqAndRespMap.put(RESP_RESULT, responseData);
		} catch (Exception e) {
			throw new RuntimeException("生成josn报文格式失败！");
		}

		return reqAndRespMap;
	}

	@Override
	public Map<String, Object> invokeWithRestXml(InvokeOpenApiParam2 param) {
		logger.info("invokeWithRestXml...");
		boolean isRest = true;
		ApiCommonParamDto dto = transferData(param);

		reqAndRespMap = new HashMap<String, Object>();

		try {
			String xml = toXml(isRest, dto);
			String requestMessage = xml;
			String responseData = doTestSoap(param.getUrl(), requestMessage);

			reqAndRespMap.put(REQ_PARAM, requestMessage);
			reqAndRespMap.put(RESP_RESULT, responseData);
		} catch (Exception e) {
			e.printStackTrace();
		}

		return reqAndRespMap;
	}

	private ApiCommonParamDto transferData(InvokeOpenApiParam2 param) {
		ApiCommonParamDto dto = new ApiCommonParamDto();
		dto.setApiVersion(param.getApiVersion());
		dto.setApiID(param.getApiId());
		dto.setAppToken(param.getAppToken());
		dto.setSysID(param.getSysId());
		dto.setAppSubId(param.getAppSubId());
		dto.setPartnerID(param.getPartnerId());
		dto.setAppPubID(param.getAppPubId());
		dto.setTimeStamp(param.getTimeStamp());

		if (StringUtils.isBlank(param.getSignMethod())) {
//			dto.setSignMethod(SIGN_METHOD_MD5);
			dto.setSignMethod("");
		} else {
			dto.setSignMethod(param.getSignMethod());
		}

		dto.setFormat(param.getFormat());
		dto.setReqdate(param.getReqdata());

		String appAppSecret = param.getAppAppSecret();
		String sign = "";

		if (SIGN_METHOD_MD5.equalsIgnoreCase(param.getSignMethod())) {
			sign = SignUtil.md5_sign(dto, appAppSecret);
		}
		
		String privateKey = param.getPrivateKey();
		if (SIGN_METHOD_RSA.equalsIgnoreCase(param.getSignMethod())) {
			sign = SignUtil.md5_sign(dto, appAppSecret);
			sign = SignUtil.rsa_encryptByPrivateKey(sign, privateKey);
		}

		dto.setSign(sign);

		logger.info(dto.toString());

		return dto;
	}

	public static String doTestSoap(String url, String xml) {
		logger.info("doTestSoap...");
		String result = "";
		CloseableHttpClient httpclient = null;
		try {
			httpclient = HttpClients.createDefault();
			HttpPost httpPost = new HttpPost(url);
			httpPost.addHeader("Content-type", "application/xml; charset=utf-8");
			httpPost.setHeader("Accept", "application/xml");
			StringEntity se = new StringEntity(xml, Charset.forName("UTF-8"));
			se.setContentType("application/xml");
			httpPost.setEntity(se);
			CloseableHttpResponse response = httpclient.execute(httpPost);
			HttpEntity entity = response.getEntity();
			if (entity != null) {
				result = EntityUtils.toString(entity, "UTF-8");
			}
			httpclient.close();
		} catch (Exception e) {
			e.printStackTrace();
		} finally {

		}
		return result;
	}

	public static String doTestJson(String url, String json) {
		String result = "";
		CloseableHttpClient httpclient = null;
		try {
			httpclient = HttpClients.createDefault();
			HttpPost httpPost = new HttpPost(url);
			httpPost.addHeader("Content-type", "application/json; charset=utf-8");
			httpPost.setHeader("Accept", "application/json");
			StringEntity se = new StringEntity(json, Charset.forName("UTF-8"));
			se.setContentType("application/json");
			httpPost.setEntity(se);
			CloseableHttpResponse response = httpclient.execute(httpPost);
			HttpEntity entity = response.getEntity();
			if (entity != null) {
				result = EntityUtils.toString(entity, "UTF-8");
			}
			httpclient.close();
		} catch (Exception e) {
			e.printStackTrace();
		} finally {

		}
		return result;
	}

	public static String toXml(boolean isRest, ApiCommonParamDto dto) throws Exception {
		StringBuilder sb = new StringBuilder(100);
		String token = dto.getAppToken();
		dto.setAppToken(null);
		String hrtAttrs = XmlUtils.bean2xml(dto);
		logger.info("========hrtAttrs=============");
		logger.info(hrtAttrs);
		if (isRest) {// restful的xml格式
			sb.append("<REQUEST>");
			sb.append(hrtAttrs);
			// sb.append("<REQUEST_DATA>");
			sb.append(dto.getReqdate());
			addToken(sb, token);
			// sb.append("</REQUEST_DATA>");
			sb.append("</REQUEST>");
		} else {
			// soap的报文格式，这里手动拼接
			sb.append("<?xml version=\"1.0\" encoding=\"UTF-8\"?>");
			sb.append(
					"<SOAP-ENV:Envelope xmlns:SOAP-ENV=\"http://schemas.xmlsoap.org/soap/envelope/\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\">");
			sb.append("<SOAP-ENV:Body>");
			sb.append("<REQUEST>");
			sb.append(hrtAttrs);
			addToken(sb, token);
			// sb.append("<REQUEST_DATA>");
			sb.append(dto.getReqdate());
			// sb.append("</REQUEST_DATA>");
			sb.append("</REQUEST>");
			sb.append("</SOAP-ENV:Body>");
			sb.append("</SOAP-ENV:Envelope>");
		}
		return sb.toString();
	}

	private static void addToken(StringBuilder sb, String token) {
		// 在</HRT_ATTRS>前面加上<App_Token>5b260c957c0d44429f10af2e551599e3</App_Token>
		int lastIndexOf = StringUtils.lastIndexOf(sb.toString(), "</HRT_ATTRS>");
		token = "<App_Token>" + token + "</App_Token>";
		sb.insert(lastIndexOf, token);
	}

}
